/*
 * This file is part of Shopping Lists Organizer software
 *
 * Copyright (C) 2011 Denis Kvita <dkvita@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 */

#include "expensesbrowser.h"

#include <QtGui>

#include "expensesmodel.h"
#include "calendar.h"
#include "chartview.h"

expensesBrowser::expensesBrowser(QWidget *parent) :
	QWidget(parent)
{
	setWindowTitle(tr("Expenses Browser"));

	QSettings cfg(qApp->property("dataDir").toString()+"/settings.ini", QSettings::IniFormat);

	expensesD= new expensesModel;

	expensesP= new QSortFilterProxyModel;
	expensesP->setSourceModel(expensesD);
	expensesP->setSortRole(Qt::EditRole);

	expensesV= new QTableView;
	expensesV->setModel(expensesP);
	expensesV->verticalHeader()->setDefaultSectionSize(22);
	expensesV->verticalHeader()->setMovable(true);
	expensesV->horizontalHeader()->setFixedHeight(22);
	expensesV->horizontalHeader()->setSortIndicatorShown(true);
	expensesV->horizontalHeader()->setMovable(true);
	expensesV->horizontalHeader()->setContextMenuPolicy(Qt::ActionsContextMenu);
	expensesV->horizontalHeader()->setTextElideMode(Qt::ElideMiddle);
	expensesV->setSortingEnabled(true);
	expensesV->setEditTriggers(QAbstractItemView::DoubleClicked|QAbstractItemView::EditKeyPressed|QAbstractItemView::AnyKeyPressed);
	expensesV->setSelectionBehavior(QAbstractItemView::SelectItems);
	expensesV->setSelectionMode(QAbstractItemView::SingleSelection);

	chartV= new chartView;

	QByteArray hDat= QByteArray::fromBase64(cfg.value("/expensesBrowser/header").toByteArray());
	if(!hDat.isEmpty()){
		hDat= qUncompress(hDat);
		if(!hDat.isEmpty()) expensesV->horizontalHeader()->restoreState(hDat);
	}

	dateBegin= new QDateEdit;
	dateBegin->setCalendarPopup(true);
	dateBegin->setCalendarWidget(new Calendar());
	if(QLocale::system().country() == QLocale::RussianFederation || QLocale::system().country() == QLocale::Ukraine) dateBegin->calendarWidget()->setFirstDayOfWeek(Qt::Monday);
	dateBegin->setDate(cfg.value("/expensesBrowser/dateBegin",QDate::currentDate()).toDate());
	connect(dateBegin, SIGNAL(dateChanged(QDate)), this, SLOT(onDateBeginChanged(QDate)));

	QLabel *dateRangeL= new QLabel("-");

	dateEnd= new QDateEdit;
	dateEnd->setCalendarPopup(true);
	dateEnd->setCalendarWidget(new Calendar());
	if(QLocale::system().country() == QLocale::RussianFederation || QLocale::system().country() == QLocale::Ukraine) dateEnd->calendarWidget()->setFirstDayOfWeek(Qt::Monday);
	dateEnd->setDate(cfg.value("/expensesBrowser/dateEnd",QDate::currentDate()).toDate());
	connect(dateEnd, SIGNAL(dateChanged(QDate)), this, SLOT(onDateEndChanged(QDate)));

	QLabel *modeL= new QLabel(tr(" show expenses by "));

	modeCB= new QComboBox;
	modeCB->addItem(tr("Date"),expensesModel::Date);
	modeCB->addItem(tr("Shop"),expensesModel::Shop);
	modeCB->addItem(tr("Category"),expensesModel::Category);
	modeCB->addItem(tr("Purchase"),expensesModel::Purchase);
	modeCB->setCurrentIndex(cfg.value("/expensesBrowser/groupingMode",0).toInt());
	connect(modeCB, SIGNAL(currentIndexChanged(int)), this, SLOT(onModeChanged(int)));

	dateModeL= new QLabel(tr(" by "));

	dateModeCB= new QComboBox;
	dateModeCB->addItem(tr("Year"),expensesModel::Year);
	dateModeCB->addItem(tr("Month"),expensesModel::Month);
	dateModeCB->addItem(tr("Day of month"),expensesModel::DayOfMonth);
	dateModeCB->addItem(tr("Day of week"),expensesModel::DayOfWeek);
	dateModeCB->setCurrentIndex(cfg.value("/expensesBrowser/dateGroupingMode",0).toInt());
	connect(dateModeCB, SIGNAL(currentIndexChanged(int)), this, SLOT(onDateModeChanged(int)));

	if(cfg.value("/expensesBrowser/groupingMode",0).toInt() != 0){
		dateModeL->hide();
		dateModeCB->hide();
	}

	QLabel *filterL= new QLabel(tr(" apply filter:"));

	filterCB= new QComboBox;
	filterCB->setEditable(true);
	filterCB->setInsertPolicy(QComboBox::InsertAfterCurrent);
	filterCB->setDuplicatesEnabled(false);
	filterCB->addItem("*");
	filterCB->completer()->setCompletionMode(QCompleter::PopupCompletion);
	filterCB->setToolTip(tr("enter a filter <br><b>'*'</b>- imply any number of any characters <br><b>'?'</b>- imply one any character"));
	connect(filterCB->lineEdit(), SIGNAL(textEdited(QString)), this, SLOT(onFilterEdited(QString)));
	connect(filterCB, SIGNAL(currentIndexChanged(int)), this, SLOT(onFilterChanged(int)));

	QLabel *sumPlanL= new QLabel(tr("Total planned: "));
	sumPlanL->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
	sumPlanV= new QLabel;
	QFont bFnt= font();
	bFnt.setBold(true);
	sumPlanV->setFont(bFnt);

	QLabel *sumBuyL= new QLabel(tr("Total bought: "));
	sumBuyL->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
	sumBuyV= new QLabel;
	sumBuyV->setFont(bFnt);

	QHBoxLayout *expLt= new QHBoxLayout;
	expLt->addWidget(dateBegin);
	expLt->addWidget(dateRangeL);
	expLt->addWidget(dateEnd);
	expLt->addWidget(modeL);
	expLt->addWidget(modeCB);
	expLt->addWidget(dateModeL);
	expLt->addWidget(dateModeCB);
	expLt->addSpacing(10);
	expLt->addWidget(filterL);
	expLt->addWidget(filterCB,1);
	expLt->setMargin(0);
	expLt->setSpacing(2);

	QHBoxLayout *sumLt= new QHBoxLayout;
	sumLt->addWidget(sumPlanL);
	sumLt->addWidget(sumPlanV);
	sumLt->addSpacing(20);
	sumLt->addWidget(sumBuyL);
	sumLt->addWidget(sumBuyV);
	sumLt->addStretch(1);
	sumLt->setMargin(0);
	sumLt->setSpacing(2);

	QTabWidget *cw= new QTabWidget;
	cw->setTabPosition(QTabWidget::South);
	cw->addTab(expensesV,QIcon(":img/table.png"),tr("Table"));
	cw->addTab(chartV,QIcon(":img/chart-pie-separate.png"),tr("Chart"));

	QVBoxLayout *mlt= new QVBoxLayout;
	mlt->addLayout(expLt);
	mlt->addWidget(cw,1);
	mlt->addLayout(sumLt);
	mlt->setMargin(3);

	setLayout(mlt);
}

void expensesBrowser::onDateBeginChanged(const QDate& date)
{
	updateData();
}

void expensesBrowser::onDateEndChanged(const QDate& date)
{
	updateData();
}

void expensesBrowser::onModeChanged(int index)
{
	if(index != 0){
		dateModeL->hide();
		dateModeCB->hide();
	}else{
		dateModeL->show();
		dateModeCB->show();
	}

	updateModelData();
	chartV->init(expensesD, expensesP, sumBuyV->text().toDouble());
}

void expensesBrowser::onDateModeChanged(int index)
{
	updateModelData();
	chartV->init(expensesD, expensesP, sumBuyV->text().toDouble());
}

void expensesBrowser::saveSettings()
{
	QSettings cfg(qApp->property("dataDir").toString()+"/settings.ini", QSettings::IniFormat);
	cfg.setValue("/expensesBrowser/dateBegin",dateBegin->date());
	cfg.setValue("/expensesBrowser/dateEnd",dateEnd->date());
	cfg.setValue("/expensesBrowser/groupingMode", modeCB->currentIndex());
	cfg.setValue("/expensesBrowser/dateGroupingMode",dateModeCB->currentIndex());
	cfg.setValue("/expensesBrowser/header",qCompress(expensesV->horizontalHeader()->saveState()).toBase64());
}

void expensesBrowser::updateTotals()
{
	double tCostP=0,tCost=0;

	for(int i=0; i<expensesP->rowCount(); i++){
		tCostP+= expensesP->mapFromSource(expensesD->index(expensesP->mapToSource(expensesP->index(i,0)).row(),2)).data().toDouble();
		tCost+= expensesP->mapFromSource(expensesD->index(expensesP->mapToSource(expensesP->index(i,0)).row(),3)).data().toDouble();
	}

	sumPlanV->setText(QString::number(tCostP,'f',2));
	sumBuyV->setText(QString::number(tCost,'f',2));
}

void expensesBrowser::updateModelData()
{
	expensesD->setMode((expensesModel::GroupingMode)modeCB->itemData(modeCB->currentIndex()).toInt());
	expensesD->setDateMode((expensesModel::DateGrouping)dateModeCB->itemData(dateModeCB->currentIndex()).toInt());
	expensesD->setPeriod(dateBegin->date(),dateEnd->date());
	expensesD->updateData();

	QAction *a;
	foreach(a,expensesV->horizontalHeader()->actions()){
		expensesV->horizontalHeader()->removeAction(a);
		delete a;
	}

	for(int i=0; i<expensesD->columnCount(); i++){
		a= new QAction(expensesD->headerData(i,Qt::Horizontal).toString(),expensesV->horizontalHeader());
		a->setData(i);
		a->setCheckable(true);
		a->setChecked(expensesV->horizontalHeader()->isSectionHidden(i) ? Qt::Unchecked : Qt::Checked );
		connect(a, SIGNAL(triggered(bool)), this, SLOT(onHeaderSectionShow(bool)));
		expensesV->horizontalHeader()->addAction(a);
	}
}

void expensesBrowser::updateData(){
	updateModelData();
	updateTotals();
	chartV->init(expensesD, expensesP, sumBuyV->text().toDouble());
}

void expensesBrowser::restore()
{
	updateData();

	QSettings cfg(qApp->property("dataDir").toString()+"/settings.ini", QSettings::IniFormat);

	QByteArray hDat= QByteArray::fromBase64(cfg.value("/expensesBrowser/header").toByteArray());
	if(!hDat.isEmpty()){
		hDat= qUncompress(hDat);
		if(!hDat.isEmpty()){
			expensesV->horizontalHeader()->restoreState(hDat);
		}
	}
}

void expensesBrowser::onHeaderSectionShow(bool isShow)
{
	QAction *act= qobject_cast<QAction*>(sender());
	if(act == 0) return;
	expensesV->horizontalHeader()->setSectionHidden(act->data().toInt(),!isShow);
}

void expensesBrowser::onFilterEdited(const QString &text)
{
	expensesP->setFilterRegExp(QRegExp(text,Qt::CaseInsensitive,QRegExp::Wildcard));
	updateTotals();

	chartV->init(expensesD, expensesP, sumBuyV->text().toDouble());
}

void expensesBrowser::onFilterChanged(int index)
{
	expensesP->setFilterRegExp(QRegExp(filterCB->itemText(index),Qt::CaseInsensitive,QRegExp::Wildcard));
	updateTotals();

	chartV->init(expensesD, expensesP, sumBuyV->text().toDouble());
}

